//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_server_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_server_api"
	"github.com/dchest/uniuri"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectServerApiImpl) GenJoinToken(ctx context.Context, req *project_server_api.GenJoinTokenRequest) (*project_server_api.GenJoinTokenResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_server_api.GenJoinTokenResponse{
			Code:   project_server_api.GenJoinTokenResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	if !(req.ServerType == project_server_api.SERVER_TYPE_SERVER_TYPE_OPEN_DRAGON_FLY || req.ServerType == project_server_api.SERVER_TYPE_SERVER_TYPE_OPEN_SEA_OTTER) {
		return &project_server_api.GenJoinTokenResponse{
			Code:   project_server_api.GenJoinTokenResponse_CODE_WRONG_SERVER_TYPE,
			ErrMsg: "错误的服务类型",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_server_api.GenJoinTokenResponse{
			Code:   project_server_api.GenJoinTokenResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_server_api.GenJoinTokenResponse{
			Code:   project_server_api.GenJoinTokenResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_server_api.GenJoinTokenResponse{
			Code:   project_server_api.GenJoinTokenResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_server_api.GenJoinTokenResponse{
			Code:   project_server_api.GenJoinTokenResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	for {
		token := uniuri.NewLen(64)
		_, ok = dao.CacheDao.GetExtServerJoinToken(ctx, token)
		if ok {
			time.Sleep(1 * time.Second)
			continue
		}
		err = dao.CacheDao.SetExtServerJoinToken(ctx, &dao.ExtServerJoinTokenDbItem{
			JoinToken:  token,
			ProjectId:  req.ProjectId,
			ServerType: uint32(req.ServerType),
		})
		if err != nil {
			return nil, err
		}
		return &project_server_api.GenJoinTokenResponse{
			Code:  project_server_api.GenJoinTokenResponse_CODE_OK,
			Token: token,
		}, nil
	}

}

func (apiImpl *ProjectServerApiImpl) GenAccessToken(ctx context.Context, req *project_server_api.GenAccessTokenRequest) (*project_server_api.GenAccessTokenResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_server_api.GenAccessTokenResponse{
			Code:   project_server_api.GenAccessTokenResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_server_api.GenAccessTokenResponse{
			Code:   project_server_api.GenAccessTokenResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_server_api.GenAccessTokenResponse{
			Code:   project_server_api.GenAccessTokenResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	isAdmin := false
	if projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin {
		isAdmin = true
	}
	userInfo, err := user_dao.UserInfoDao.Get(ctx, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	for {
		token := uniuri.NewLen(64)
		_, ok = dao.CacheDao.GetExtServerAccessToken(ctx, token)
		if ok {
			time.Sleep(1 * time.Second)
			continue
		}
		err = dao.CacheDao.SetExtServerAccessToken(ctx, &dao.ExtServerAccessTokenDbItem{
			AccessToken:       token,
			ProjectId:         req.ProjectId,
			MemberUserId:      sessionItem.UserId,
			MemberDisplayName: userInfo.BasicInfo.DisplayName,
			MemberLogoUri:     userInfo.BasicInfo.LogoUri,
			MemberIsAdmin:     isAdmin,
		})
		if err != nil {
			return nil, err
		}
		return &project_server_api.GenAccessTokenResponse{
			Code:  project_server_api.GenAccessTokenResponse_CODE_OK,
			Token: token,
		}, nil
	}
}

func (apiImpl *ProjectServerApiImpl) JoinByJoinToken(ctx context.Context, req *project_server_api.JoinByJoinTokenRequest) (*project_server_api.JoinByJoinTokenResponse, error) {
	joinItem, ok := dao.CacheDao.GetExtServerJoinToken(ctx, req.Token)
	if !ok {
		return &project_server_api.JoinByJoinTokenResponse{
			Code:   project_server_api.JoinByJoinTokenResponse_CODE_WRONG_TOKEN,
			ErrMsg: "访问令牌不存在",
		}, nil
	}
	serverId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.ServerDao.Insert(sessCtx, &project_dao.ServerInfoDbItem{
			ServerId:  serverId,
			ProjectId: joinItem.ProjectId,
			BasicInfo: project_dao.BasicServerInfoDbItem{
				ServerName:       req.ServerName,
				ServerType:       joinItem.ServerType,
				AddrList:         []string{req.ServerAddr},
				ExternServerType: 0,
			},
			ShareSecret: req.ShareSecret,
			CreateTime:  nowTime,
			UpdateTime:  nowTime,
		})
		if err != nil {
			return nil, err
		}
		return &project_server_api.JoinByJoinTokenResponse{
			Code:      project_server_api.JoinByJoinTokenResponse_CODE_OK,
			ServerId:  serverId,
			ProjectId: joinItem.ProjectId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*project_server_api.JoinByJoinTokenResponse), nil
}

func (apiImpl *ProjectServerApiImpl) QueryByAccessToken(ctx context.Context, req *project_server_api.QueryByAccessTokenRequest) (*project_server_api.QueryByAccessTokenResponse, error) {
	accessToken, ok := dao.CacheDao.GetExtServerAccessToken(ctx, req.Token)
	if !ok {
		return &project_server_api.QueryByAccessTokenResponse{
			Code:   project_server_api.QueryByAccessTokenResponse_CODE_WRONG_TOKEN,
			ErrMsg: "访问令牌不存在",
		}, nil
	}

	return &project_server_api.QueryByAccessTokenResponse{
		Code:              project_server_api.QueryByAccessTokenResponse_CODE_OK,
		ProjectId:         accessToken.ProjectId,
		MemberUserId:      accessToken.MemberUserId,
		MemberDisplayName: accessToken.MemberDisplayName,
		MemberLogoUri:     accessToken.MemberLogoUri,
		MemberIsAdmin:     accessToken.MemberIsAdmin,
	}, nil
}
